package tools

import java.io.File

import config.{Global, MyFile}
import org.apache.commons.io.FileUtils
import play.api.data.Form
import play.api.data.FormBinding.Implicits._
import play.api.data.Forms._
import play.api.libs.json.Json
import play.api.mvc.{AnyContent, MultipartFormData, Request}
import utils.ExecCommand

import scala.jdk.CollectionConverters._

object Muscle extends MyFile {

  case class MuscleData(method: String, queryText: String, tree: String)

  val MuscleForm: Form[MuscleData] = Form(
    mapping(
      "method" -> text,
      "queryText" -> text,
      "tree" -> text
    )(MuscleData.apply)(MuscleData.unapply)
  )

  def muscle(implicit request: Request[MultipartFormData[File]]) = {
    var valid = "true"
    var msg = ""
    var out = ""
    var treeJson = ""
    try {

      val data = MuscleForm.bindFromRequest.get
      val tmpDir = java.nio.file.Files.createTempDirectory("tmpDir").toString
      val seqFile = new File(tmpDir, "seq.fa")
      data.method match {
        case "text" =>
          FileUtils.writeStringToFile(seqFile, data.queryText)
        case "file" =>
          val file = request.body.file("file").get
          file.ref.moveToFile(seqFile)
      }

      val xx = FileUtils.readLines(seqFile).asScala
      val e = xx.map { x =>
        if (x.startsWith(">")) {
          x.split(" ").head
        } else {
          x
        }
      }

      FileUtils.writeLines(new File(tmpDir + "/seqs.fa"), e.asJava)
      val outFile = tmpDir + "/result.txt"
      val execCommand = new ExecCommand
      val commandBuffer = "muscle -in " + tmpDir + "/seqs.fa" + " -verbose -log  -fasta  -out " + outFile + " -group "
      val treeFile = new File(tmpDir, "tree.txt")
      val tree = data.tree match {
        case "none" => " "
        case "tree1" => " -tree1 " + treeFile.getAbsolutePath
        case "tree2" => " -tree2 " + treeFile.getAbsolutePath
      }
      val command1 = commandBuffer + tree
      execCommand.exect(Array(command1), tmpDir)
      if (execCommand.isSuccess) {
        treeJson = if (!treeFile.exists()) "" else FileUtils.readFileToString(treeFile)
        out = FileUtils.readFileToString(new File(outFile))
      } else {
        valid = "false";
        msg = execCommand.getErrStr
      }

      tmpDir.delete
    } catch {
      case e: Exception => valid = "false"; msg = e.getMessage
    }
    if (Global.isWindow) {
      treeJson = s"${Global.testResult}/muscle/tree.txt".readFileToString
      out = s"${Global.testResult}/muscle/result.txt".readFileToString
      valid="true"
    }
    Json.obj("valid" -> valid,"msg" -> msg,"out"->out,"tree"->treeJson)

  }


  case class SvgData(svgHtml: String)

  val svgForm = Form(
    mapping(
      "svgHtml" -> text
    )(SvgData.apply)(SvgData.unapply)
  )

  def getDownloadTree(implicit request: Request[AnyContent]): File = {
    val data = svgForm.bindFromRequest().get
    val dataFile = java.nio.file.Files.createTempFile("tmp", ".svg").toFile
    val str = data.svgHtml.replaceAll("</svg>", "\n" + phylotreeCss + "</svg>")
    FileUtils.writeStringToFile(dataFile, str, "UTF-8")
    dataFile
  }


  val phylotreeCss =
    """
      |<style>
      |.tree-selection-brush .extent {
      |    fill-opacity: .05;
      |    stroke: #fff;
      |    shape-rendering: crispEdges;
      |}
      |
      |.tree-scale-bar text {
      |  font: sans-serif;
      |}
      |
      |.tree-scale-bar line,
      |.tree-scale-bar path {
      |  fill: none;
      |  stroke: #000;
      |  shape-rendering: crispEdges;
      |}
      |
      |.node circle, .node ellipse, .node rect {
      |fill: steelblue;
      |stroke: black;
      |stroke-width: 0.5px;
      |}
      |
      |.internal-node circle, .internal-node ellipse, .internal-node rect{
      |fill: #CCC;
      |stroke: black;
      |stroke-width: 0.5px;
      |}
      |
      |.node {
      |font: 10px sans-serif;
      |}
      |
      |.node-selected {
      |fill: #f00 !important;
      |}
      |
      |.node-collapsed circle, .node-collapsed ellipse, .node-collapsed rect{
      |fill: black !important;
      |}
      |
      |.node-tagged {
      |fill: #00f;
      |}
      |
      |.branch {
      |fill: none;
      |stroke: #999;
      |stroke-width: 2px;
      |}
      |
      |.clade {
      |fill: #1f77b4;
      |stroke: #444;
      |stroke-width: 2px;
      |opacity: 0.5;
      |}
      |
      |.branch-selected {
      |stroke: #f00 !important;
      |stroke-width: 3px;
      |}
      |
      |.branch-tagged {
      |stroke: #00f;
      |stroke-dasharray: 10,5;
      |stroke-width: 2px;
      |}
      |
      |.branch-tracer {
      |stroke: #bbb;
      |stroke-dasharray: 3,4;
      |stroke-width: 1px;
      |}
      |
      |
      |.branch-multiple {
      |stroke-dasharray: 5, 5, 1, 5;
      |stroke-width: 3px;
      |}
      |
      |.branch:hover {
      |stroke-width: 10px;
      |}
      |
      |.internal-node circle:hover, .internal-node ellipse:hover, .internal-node rect:hover {
      |fill: black;
      |stroke: #CCC;
      |}
      |
      |.tree-widget {
      |}
      |</style>
    """.stripMargin

}
